package com.bizframework.core.testcase.interagtion.dao;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Set;
import java.util.UUID;

import org.unitils.util.ReflectionUtils;

public class EntityUtils {

	public static int maxString = -1;

	public static int maxInt = Integer.MAX_VALUE;

	public static int minInt = Integer.MIN_VALUE;

	public static <T> T createRandomEntity(Class<T> entityType)
			throws Exception {
		T entity = createNewEntity(entityType);
		createRandomEntity(entity, true);
		return entity;
	}

	public static <T> T createRandomEntity(Class<T> entityType, Boolean setId)
			throws Exception {
		T entity = createNewEntity(entityType);
		createRandomEntity(entity, setId);
		return entity;
	}

	public static <T> void createRandomEntity(T entity, Boolean setId)
			throws Exception {
		if (entity != null) {
			HashMap<String, Type> typeArguments = new HashMap<String, Type>();
			Set<Field> fields = ReflectionUtils.getAllFields(entity.getClass());

			if (setId) {
				Type superclassType = entity.getClass().getGenericSuperclass();
				if (superclassType instanceof ParameterizedType) {
					Type[] typeArgumentTypes = ((ParameterizedType) superclassType)
							.getActualTypeArguments();
					for (int i = 0; i < typeArgumentTypes.length; i++) {
						Type argType = (Class<?>) typeArgumentTypes[i];
						typeArguments.put("IDT", argType);
					}
				}
			}
			for (Field field : fields) {
				createRandomField(entity, field, typeArguments);
			}
		}
	}

	private static <T> void createRandomField(T entity, Field field,
			HashMap<String, Type> typeArguments) throws Exception {
		Method setter = ReflectionUtils.getSetter(entity.getClass(), field
				.getName(), false);

		if (setter != null) {
			Object value = null;
			if (typeArguments.containsKey(field.getGenericType().toString())) {
				value = getRandomValue(typeArguments.get(field.getGenericType()
						.toString()));
			} else {
				value = getRandomValue(field.getGenericType());
			}

			ReflectionUtils.invokeMethod(entity, setter, value);
		}
	}

	@SuppressWarnings("unchecked")
	private static <T> T getRandomValue(Type type) {
		Object value = null;
		if (type == String.class) {
			value = UUID.randomUUID().toString();
			if (maxString > 0) {
				value = value.toString().substring(0, maxString);
			}
		} else if (type == Integer.class) {
			value = new java.util.Random().nextInt(maxInt);
		} else if (type == Date.class) {
			value = new Date();
		} else if (type == Boolean.class) {
			value = new java.util.Random().nextBoolean();
		} else if (type == Double.class) {
			BigDecimal b = new BigDecimal(new java.util.Random().nextDouble());
			value = Double.parseDouble(b.setScale(1, BigDecimal.ROUND_HALF_UP)
					.toString());
		} else if (type == Float.class) {
			BigDecimal b = new BigDecimal(new java.util.Random().nextFloat());
			value = Float.parseFloat(b.setScale(1, BigDecimal.ROUND_HALF_UP)
					.toString());
		} else if (type == Long.class) {
			value = (long) new java.util.Random().nextInt(maxInt);
		}
		return (T) value;
	}

	public static <T> T createNewEntity(Class<T> entityType) throws Exception {
		T entity = entityType.newInstance();
		return entity;
	}
}
